iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Software Development

從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰系列 第 14

Day 14 - 虛擬磁碟的誕生:如何用 dd 與 mkdosfs 憑空捏出一個 FAT32 空間?

  • 分享至 

  • xImage
  •  

[!NOTE]
本系列文章已進行全域去敏與匿名化處理,專案代號統一為 DataGateway,內網 IP 統一為 10.0.0.x

在前面的章節中,我們已經成功利用 ConfigFS 騙過了 Windows 電腦,讓它以為插上來的是一顆「隨身碟」(Mass Storage Device)。
但在 Windows 端看到隨身碟跳出來,並不代表你可以存取資料。如果沒有提供儲存空間,Windows 會殘酷地跳出:「請插入磁片」或「磁碟未格式化」。

我們需要餵給這顆「隨身碟」一個實際存在的儲存空間。但問題來了,Raspberry Pi 只有一張 SD 卡(檔案系統是 ext4),我們總不能把整張作業系統的 SD 卡直接掛給 Windows 讀取吧?Windows 原生根本不認識 ext4

因此,我們需要第三階段的核心技術:虛擬磁碟 (Virtual Disk Image)

問題情境:Windows 只懂 FAT32 / exFAT

在醫療邊緣設備的場景中,護理師或醫生會把 DataGateway 從感測器端拔下來,然後插上護理站的 Windows 電腦來讀取裡面的 CSV 報表。

為了確保相容性,這個 USB 空間必須是 Windows 原生支援的格式,最通用的選擇就是 FAT32

我們的策略是:在 Raspberry Pi 的 ext4 檔案系統內,建立一個巨大的「檔案」,然後把這個「檔案」當作一塊空白硬碟,將它格式化成 FAT32,最後把這塊「檔案」餵給 USB Gadget 的 LUN (Logical Unit Number)。

這聽起來很像虛擬機 (VM) 的虛擬硬碟檔 (.vdi.vmdk) 對吧?沒錯,概念完全一樣!

步驟一:用 dd 指令無中生有

Linux 有一個古老且威力強大的工具叫做 dd (Data Duplicator,也有人戲稱它叫 Disk Destroyer)。它可以用來位元對位元地複製資料。

我們要用它從 /dev/zero (這是一個會無限吐出 0x00 的特殊設備) 抓取資料,寫入到我們指定的路徑,藉此「撐」出一個指定大小的實體檔案。

# 在 /opt/gateway 目錄下,建立一個名為 usb_disk.img 的檔案
# bs=1M (每次寫入 1MB)
# count=256 (寫入 256 次)
# 最終會產生一個 256MB 的空白檔案
sudo dd if=/dev/zero of=/opt/gateway/usb_disk.img bs=1M count=256

執行完畢後,用 ls -lh 觀察,你會看到一個扎扎實實佔用 256MB 空間的 usb_disk.img
這就是我們的「實體硬碟」了,只是它現在裡面全是 0x00,什麼格式都沒有。

步驟二:用 mkdosfs 格式化為 FAT32

接下來,我們要對這顆剛出廠的「空白硬碟」進行格式化。
因為 Windows 認得 FAT32,所以我們需要安裝 dosfstools

sudo apt-get update
sudo apt-get install dosfstools -y

接著,使用 mkdosfs (或是 mkfs.vfat) 直接對這個 .img 檔案進行格式化。

[!WARNING]
通常格式化指令是針對 /dev/sda1 這種磁區 (Partition),但 Linux 強大的地方就在於,它允許你直接對一般檔案進行格式化

# -F 32 : 指定格式為 FAT32
# -I    : 強制對整個裝置 (不分區) 進行格式化
# -n    : 設定磁碟區標籤 (Volume Label) 為 DATADOCK
sudo mkdosfs -F 32 -I -n "DATADOCK" /opt/gateway/usb_disk.img

執行完畢後,這顆 usb_disk.img 已經不是一個普通的檔案了,它內部現在擁有完整的 FAT32 檔案分配表 (File Allocation Table) 結構!

步驟三:餵給 USB ConfigFS

回到我們 Day 10 寫的 ConfigFS 腳本。在 Mass Storage 的 LUN 設定中,我們要把剛剛做好的 usb_disk.img 綁定進去:

# 假設你已經建立好 mass_storage.0
cd /sys/kernel/config/usb_gadget/gateway_gadget/functions/mass_storage.0

# 將 img 檔案的路徑寫入 LUN 0 的 file 屬性中
echo "/opt/gateway/usb_disk.img" > lun.0/file

# 確保它是不可移除的唯讀/讀寫隨身碟 (視你的設計而定)
echo 0 > lun.0/removable
echo 0 > lun.0/cdrom

只要確保這一切都在 Day 13 提到的 echo UDC_NAME > UDC (點火) 之前完成即可。

小結與伏筆

現在,如果你把 Raspberry Pi 透過 Type-C 連接線插上 Windows 電腦,Windows 就會發出清脆的「登愣」聲,並且彈出一個名為 DATADOCK 的 256MB 隨身碟!

這感覺非常神奇,我們用純軟體的方式,在樹莓派裡憑空捏出了一個隨身碟給 PC 讀取。

但是,危機也在此刻埋下。
如果 Windows 正在讀取這顆 FAT32 磁碟,那 Raspberry Pi 內部的 Python 程式該怎麼把 Edge Sensor 的最新感測資料寫進這個 FAT32 空間裡呢?

我們總不能讓 Pi 和 Windows 同時對同一個 FAT32 結構進行寫入吧?
這就是邊緣儲存設備最令人聞風喪膽的 雙腦分裂 (Split-Brain) 問題。

為了解決這個問題,明天我們必須先學習 Linux 黑魔法中的黑魔法:Loop Device (losetup)。


上一篇
Day 13 - 完美點火:如何寫出一支跨硬體 (Pi 3 / Pi 4) 的自動 UDC 綁定腳本?
下一篇
Day 15 - losetup 的藝術:如何優雅地掛載與回收 Loop Device?
系列文
從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言